#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include "eXosip2/eXosip2.h"  
#include "eXosip2/eX_call.h"
#include "eXosip2/eX_setup.h"
#include "osipparser2/osip_parser.h" 
#include "osipparser2/osip_message.h"
#include "osipparser2/osip_body.h"

#include "od_trace.h"
#include "od_task.h"
#include "od_os.h"
#include "od_engine.h"
#include "od_sip_sdp.h"
#include "od_sip_comn.h"
#include "od_sip_state_machine.h"
#include "od_sip_handle_event.h"
#include "od_sip_message.h"
#include "od_sip_timer.h"
#include "od_sip_event_distributor.h"


#define SIP_HANDLE_EVENT_TSK_STACK_SIZE  (4*1024 * 1024)   /*线程栈资源大小*/


typedef struct
{
    TASK_COMMON_MEMBERS

    int in_cid;
    pipeline_handle g_event_pipe;
    void **h_state_machine;
    int did;
    od_sip_ctx *ctx;
    od_sip_session_ctx session_ctx;
    eXosip_event_t *event;
    bool is_invite_ack;
    int group_id;
    od_sip_event_queue evt_que;
}od_sip_hdl_evt_obj;



params_def od_sip_handle_event_dynamic_params_def[]=
{
    {OFFSET(od_sip_handle_event_dynamic_params, request_status), PT_VAR_INT32 | PT_REAL_TIME, sizeof(int), 0, 1},
    {OFFSET(od_sip_handle_event_dynamic_params, username), PT_VAR_STR | PT_REAL_TIME, sizeof(char), 0, 32},
    {OFFSET(od_sip_handle_event_dynamic_params, bye_flg), PT_VAR_INT32 | PT_REAL_TIME, sizeof(int), 0, 1},
    {0, 0, 0, 0, 0}
};

const od_sip_handle_event_dynamic_params glb_sip_handle_event_dynamic_params_default = 
{
    0,                     /*request_status*/
    "13601151245",         /*request_uri*/
    0                      /*bye_flg*/
};

static void sip_hdl_evt_reset_all_status_flg(od_sip_hdl_evt_obj *obj)
{
    od_sip_handle_event_dynamic_params *param = obj->params;

    param->bye_flg = 0;
    param->request_status = 0;
    obj->in_cid = -1;
    obj->did = -1;
    obj->is_invite_ack = false;
    memset(&obj->session_ctx, 0, sizeof(obj->session_ctx));
    obj->ctx->share->se_timer.refresh_cnt = 0;
}

static void sip_hdl_evt_session_close(od_sip_hdl_evt_obj *obj)
{
    obj->malloc_free_rst = DEF_RST;
    obj->real_time_rst = DEF_RST;
}

static void sip_hdl_evt_send_bye(od_sip_hdl_evt_obj *obj)
{
    eXosip_lock(obj->ctx->ex_ctx);
    eXosip_call_terminate(obj->ctx->ex_ctx, obj->in_cid, obj->did);
    eXosip_unlock(obj->ctx->ex_ctx);

    /*reset local encoder/decoder*/
    if (obj->ctx->cb.codec_cb.reset_codec)
        obj->ctx->cb.codec_cb.reset_codec(obj->ctx->cb.codec_cb.h_codec);

    set_phone_status(*obj->h_state_machine, PHONE_STATUS_HANG);
    sip_hdl_evt_session_close(obj);
}

static void sip_hdl_evt_add_header(od_sip_hdl_evt_obj *obj, osip_message_t *answer)
{
    char buf[64];
    
    osip_message_set_allow(answer, ALLOW_STRING); 
    osip_message_set_supported(answer, SUPPORT_STRING);    
    if (obj->ctx->share->se_timer.refresher != RFH_UNKNOWN) {
        snprintf(buf, sizeof(buf), "%d", obj->ctx->share->se_timer.sess_expires);
    } else {
        snprintf(buf, sizeof(buf), "%d;refresher=uas", obj->ctx->share->se_timer.sess_expires); 
        obj->ctx->share->se_timer.refresher = RFH_UAS;
    }
    osip_message_set_header(answer, Session_Expires, buf);
    osip_message_set_content_type(answer, CONTENT_TYPE_STRING);  
}

static int sip_hdl_evt_call_invite(od_sip_hdl_evt_obj *obj)
{
    od_sip_handle_event_dynamic_params *param = obj->params;
    osip_uri_t *uri = NULL;
    char *remote_sdp_char = NULL;
    od_media_config capa_cfg;
    osip_body_t *body = NULL;
    size_t str_length;
        
    if (get_phone_status(*obj->h_state_machine) != PHONE_STATUS_AVAILABLE) {
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_BUSY_HERE);
        RPTWRN("I AM BUSY NOW!!:-)");
        return OD_ERROR;
    }
    set_phone_status(*obj->h_state_machine, PHONE_STATUS_NEW_CALL_COMING);

    /*step 1: save uri->username for UI display*/
    uri = osip_message_get_uri(obj->event->request);
    if (!uri) {
        RPTERR("get uri error!!");
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_UNSUPPORTED_URI_SCHEME);
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_UNSUPPORT_MEDIA_TYPE);
        return OD_ERROR;
    }

    /*save username for UI display*/
    if (uri->username)
        snprintf(param->username, sizeof(param->username), "%s", uri->username);

    /*send 180-ring*/
    od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_RINGING);
    set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_RINGING);

    /*parse timer*/
    if (od_sip_timer_process_req(obj->ctx, obj->event) != OD_OK) {
        osip_message_t *answer;
        char buf[64];
    
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_MEDIA_ERR);
        eXosip_lock(obj->ctx->ex_ctx);
        if (!eXosip_call_build_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_SESSION_TIMER_TOO_SMALL, &answer)) {
            snprintf(buf, sizeof(buf), "%d", obj->ctx->share->se_timer.min_se);
            osip_message_set_header(answer, Min_SE, buf);
            eXosip_call_send_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_SESSION_TIMER_TOO_SMALL, answer);
        }
        eXosip_unlock(obj->ctx->ex_ctx);    
        return OD_ERROR;
    }

    /*step 2: get remote sdp in string*/
    if (!obj->event->request) {
        RPTERR("INVITE request NULL,error!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }
    
    if (osip_message_get_body(obj->event->request, 0, &body) < 0) {
        RPTERR("get remote INVITE body error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }

    if (osip_body_to_str(body, &remote_sdp_char, &str_length) < 0) {
        RPTERR("body to str error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }
    
    /*step 3: negotiate remote sdp with local capa*/
    if (obj->ctx->cb.cfg_cb.get_capa) //get local encoder/decoder capabilty
        obj->ctx->cb.cfg_cb.get_capa(obj->ctx->cb.cfg_cb.h_callback, &capa_cfg);

    obj->session_ctx.local_capa_config = &capa_cfg;
    obj->session_ctx.session_sdp_neg.session_type = OD_REMOTE_OFFER;
    if (od_media_sdp_negotiate(obj->ctx, 
                               remote_sdp_char, 
                               str_length, 
                               &obj->session_ctx) != PJ_SUCCESS) {
        RPTERR("sdp negotiate error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_UNSUPPORT_MEDIA_TYPE);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_UNSUPPORTED_MEDIA_TYPE);
        return OD_ERROR;
    }    

    /*TODO:pick-up phone?*/

    /*setp 4: return 200-OK with SDP*/
    {
        osip_message_t *answer = NULL;
        char result_sdp[1024] = {0};

        if (od_media_sdp_print(obj->session_ctx.session_sdp_neg.active_local_sdp,
                               result_sdp,
                               sizeof(result_sdp)) < 0) {
            RPTERR("result_sdp buf too short!!!");
            set_phone_status(*obj->h_state_machine, PHONE_STATUS_UNSUPPORT_MEDIA_TYPE);
            od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_BAD_EXTENSION);
            return OD_ERROR;
        }

        eXosip_lock(obj->ctx->ex_ctx);
        eXosip_call_build_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_OK, &answer);
        sip_hdl_evt_add_header(obj, answer);
        osip_message_set_body(answer, result_sdp, strlen(result_sdp));
        eXosip_call_send_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_OK, answer);
        eXosip_unlock(obj->ctx->ex_ctx);
    }

    /*step 5: restore did & cid*/
    obj->did = obj->event->did;
    obj->in_cid = obj->event->cid;
    obj->is_invite_ack = true;
    
    set_phone_status(*obj->h_state_machine, PHONE_STATUS_SEND_200OK);

    return OD_OK;        
}

static int sip_hdl_evt_call_ack(od_sip_hdl_evt_obj *obj)
{
    od_sip_handle_event_dynamic_params *param = obj->params;
    
    if (obj->in_cid == obj->event->cid
            && obj->is_invite_ack == true) {
        /*set negotiate result set to local encoder/decoder*/
        if (obj->ctx->cb.cfg_cb.set_cfg) { 
            od_media_params *decode_param = &obj->session_ctx.decode_media;
            od_media_params *encode_param = &obj->session_ctx.encode_media;
            obj->ctx->cb.cfg_cb.set_cfg(obj->ctx->cb.cfg_cb.h_callback, decode_param);
            obj->ctx->cb.cfg_cb.set_cfg(obj->ctx->cb.cfg_cb.h_callback, encode_param);
        }

        RPTDBG("invite ACK recv!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_CONVERSATION);
        param->request_status = 1;
        obj->is_invite_ack = false;
        obj->ctx->share->se_timer.last_refresh_time = od_sip_getCurTimeInMsec();
    }else {
        RPTWRN("not my ACK!!");
    }

    return OD_OK;
}

static int sip_hdl_evt_call_release(od_sip_hdl_evt_obj *obj)
{
    if (obj->in_cid == obj->event->cid) {
        if (obj->ctx->cb.codec_cb.reset_codec) //reset encoder/decoder
            obj->ctx->cb.codec_cb.reset_codec(obj->ctx->cb.codec_cb.h_codec);
        RPTDBG("call release!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_RELEASE);
        sip_hdl_evt_session_close(obj);
    }

    return OD_OK;
}


static int sip_hdl_evt_call_close(od_sip_hdl_evt_obj *obj)
{
    if (obj->in_cid != obj->event->cid) {
        RPTDBG("not my BYE!!!");
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_CALL_TRANSACTION_DOES_NOT_EXIST);
        return OD_OK;
    }

    /*reset encoder/decoder*/
    if (obj->ctx->cb.codec_cb.reset_codec) 
        obj->ctx->cb.codec_cb.reset_codec(obj->ctx->cb.codec_cb.h_codec);

    set_phone_status(*obj->h_state_machine, PHONE_STATUS_HANG);
    sip_hdl_evt_session_close(obj);
    
    return OD_OK;
}


/**
* If there is an error in the session modification during the call, 
* the original call shall be maintained and the call state shall not be changed,
* in other word, do not call the #set_phone_status function.
*/
static int sip_hdl_evt_call_reinvite(od_sip_hdl_evt_obj *obj)
{
    char *remote_sdp_char = NULL;
    od_media_config capa_cfg;
    osip_body_t *body = NULL;
    size_t str_length;
    
    OD_SIP_ASSERT_RETURN(obj->event, OD_ERROR);

    /*step 1：get remote SDP to string*/
    if (!obj->event->request) {
        RPTERR("INVITE request NULL,error!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }
    
    if (osip_message_get_body(obj->event->request, 0, &body) < 0) {
        RPTERR("get remote INVITE body error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }

    if (osip_body_to_str(body, &remote_sdp_char, &str_length) < 0) {
        RPTERR("body to str error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_NOT_ACCEPTABLE_HERE);
        return OD_ERROR;
    }

    /*parse timer*/
    if (od_sip_timer_process_req(obj->ctx, obj->event) != OD_OK) {
        osip_message_t *answer;
        char buf[64];
    
        eXosip_lock(obj->ctx->ex_ctx);
        if (!eXosip_call_build_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_SESSION_TIMER_TOO_SMALL, &answer)) {
            snprintf(buf, sizeof(buf), "%d", obj->ctx->share->se_timer.min_se);
            osip_message_set_header(answer, Min_SE, buf);
            eXosip_call_send_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_SESSION_TIMER_TOO_SMALL, answer);
        }
        eXosip_unlock(obj->ctx->ex_ctx);
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_MEDIA_ERR);
        return OD_ERROR;
    }

    /*step 2: negotiate*/
    if (obj->ctx->cb.cfg_cb.get_capa) //get local encoder/decoder capabilty
        obj->ctx->cb.cfg_cb.get_capa(obj->ctx->cb.cfg_cb.h_callback, &capa_cfg);

    obj->session_ctx.local_capa_config = &capa_cfg;
    obj->session_ctx.session_sdp_neg.session_type = OD_REMOTE_OFFER;
    if (od_media_sdp_negotiate(obj->ctx, 
                               remote_sdp_char, 
                               str_length, 
                               &obj->session_ctx) != PJ_SUCCESS) {
        RPTERR("sdp negotiate error!!");
        set_phone_status(*obj->h_state_machine, PHONE_STATUS_MEDIA_ERR);
        od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_UNSUPPORTED_MEDIA_TYPE);
        return OD_ERROR;
    }    

    /*setp 3: return 200OK with SDP*/
    {
        osip_message_t *answer = NULL;
        char result_sdp[1024] = {0};

        if (od_media_sdp_print(obj->session_ctx.session_sdp_neg.active_local_sdp,
                               result_sdp,
                               sizeof(result_sdp)) < 0) {
            RPTERR("result_sdp buf too short!!!");
            set_phone_status(*obj->h_state_machine, PHONE_STATUS_LOCAL_ERR);
            od_sip_call_send_answer_with_code(obj->ctx->ex_ctx, obj->event, SIP_UNSUPPORTED_MEDIA_TYPE);
            return OD_ERROR;
        }

        eXosip_lock(obj->ctx->ex_ctx);
        eXosip_call_build_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_OK, &answer);
        sip_hdl_evt_add_header(obj, answer);
        osip_message_set_body(answer, result_sdp, strlen(result_sdp));
        eXosip_call_send_answer(obj->ctx->ex_ctx, obj->event->tid, SIP_OK, answer);
        eXosip_unlock(obj->ctx->ex_ctx);
    }

    /*restore did*/
    obj->did = obj->event->did;
    obj->is_invite_ack = true;
                               
    return OD_OK;
}


static int sip_hdl_evt_handle_event(od_sip_hdl_evt_obj *obj)
{
    int retval = OD_OK;
    
    switch (obj->event->type)  
    {  
        case EXOSIP_CALL_INVITE:   
            RPTDBG("EXOSIP_CALL_INVITE");
            retval = sip_hdl_evt_call_invite(obj);
            break;
            
        case EXOSIP_CALL_ACK: 
            RPTDBG("EXOSIP_CALL_ACK");
            retval = sip_hdl_evt_call_ack(obj);
            break;  

        case EXOSIP_CALL_RELEASED:  
            RPTDBG("EXOSIP_CALL_RELEASED");
            retval = sip_hdl_evt_call_release(obj);
            break;

        case EXOSIP_CALL_CLOSED:   
            RPTDBG("EXOSIP_CALL_CLOSED");
            retval = sip_hdl_evt_call_close(obj);
            break;  

        case EXOSIP_CALL_MESSAGE_NEW:  
            RPTDBG("EXOSIP_CALL_MESSAGE_NEW");
            retval = od_sip_msg_call_message_new(obj->ctx, obj->event, obj->in_cid);
            break; 

        case EXOSIP_CALL_REINVITE: 
            RPTDBG("EXOSIP_CALL_REINVITE");
            retval = sip_hdl_evt_call_reinvite(obj);
            break;

        case EXOSIP_CALL_ANSWERED: 
            RPTDBG("EXOSIP_CALL_ANSWERED");
            /*TODO*/
            break;

        case EXOSIP_CALL_MESSAGE_ANSWERED: 
            RPTDBG("EXOSIP_CALL_MESSAGE_ANSWERED");
            retval = od_sip_msg_call_message_answerd(obj->ctx, obj->event);
            break;

        case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:          
            RPTDBG("EXOSIP_CALL_MESSAGE_REQUESTFAILURE");
            /*TODO*/
            break;

        default:
            RPTWRN("un-process:[%s]\n", obj->event->textinfo);
            break;
    }

    eXosip_event_free(obj->event);
    return retval;
}

static void sip_hdl_evt_monitor_conversation(od_sip_hdl_evt_obj *obj)
{
    od_sip_handle_event_dynamic_params *param = obj->params;

    if (param->request_status == 0)
        return;

    if (param->bye_flg) {
        sip_hdl_evt_send_bye(obj);
    }

    if (obj->ctx->share->se_timer.refresher != RFH_UNSUPPORT) {
        uint32_t refresh_interval = (od_sip_getCurTimeInMsec() \
                                    - obj->ctx->share->se_timer.last_refresh_time)/1000; //unit:second
        if (refresh_interval > (obj->ctx->share->se_timer.sess_expires/2)) {
            if (obj->ctx->share->se_timer.refresher == RFH_UAS) {
                od_sip_timer_create_update_req(obj->ctx, obj->did);
            }

            obj->ctx->share->se_timer.last_refresh_time = od_sip_getCurTimeInMsec();
            if (++(obj->ctx->share->se_timer.refresh_cnt) 
                    >= obj->ctx->share->se_timer.max_fail_times) {
                sip_hdl_evt_send_bye(obj);
            }
        }
    }
}


/*Monitor the session process and respond to user control instructions*/
static void sip_hdl_evt_monitor(od_sip_hdl_evt_obj *obj)
{
    switch(get_phone_status(*obj->h_state_machine))
    {
        case PHONE_STATUS_CONVERSATION:
            sip_hdl_evt_monitor_conversation(obj);
            break;
        
        default:
            break;
    }
}


static int sip_hdl_evt_start_stop(od_sip_hdl_evt_obj *obj)
{
    static pj_thread_desc thread_desc;
    pj_thread_t *thread;
    pipeline_attrs fAttrs = pipeline_attrs_default;

    obj->ctx = od_sip_lib_start();
    OD_SIP_ASSERT_RETURN(obj->ctx, OD_EFAULT);

    if (!pj_thread_is_registered()) {
        pj_bzero(thread_desc, sizeof(pj_thread_desc));
        pj_thread_register(obj->task_name, thread_desc, &thread);
    }

    /*create event pipe*/
    obj->g_event_pipe = pipeline_create(&fAttrs);
    if (!obj->g_event_pipe) {
        RPTERR("create event pipe error!!");
        return OD_ERROR;
    }

    /*register to event distributor pthread to get event!!*/
    obj->evt_que.tsk_id = obj->group_id;
    obj->evt_que.obj_id = &obj->in_cid;
    obj->evt_que.tsk_name = obj->task_name;
    obj->evt_que.queue_type = OD_SIP_EVT_QUEUE_TYPE_HANDLE_EVENT;
    obj->evt_que.g_event_pipe = obj->g_event_pipe;
    if (od_sip_evt_distrb_add(&obj->evt_que) != OD_OK) {
        RPTERR("add handle_event que pipe error!");
        return OD_ERROR;
    }

    /*wait until STATE-MACHINE start!!*/
    while(*obj->h_state_machine == NULL)
        od_msleep(100);

    return OD_OK;
}

static void sip_hdl_evt_start_stop_delete(od_sip_hdl_evt_obj *obj)
{
    od_sip_lib_stop();
    od_sip_evt_distrb_remove(&obj->evt_que);
    pipeline_delete(obj->g_event_pipe);
}

static int sip_hdl_evt_malloc_free(od_sip_hdl_evt_obj *obj)
{
    sip_hdl_evt_reset_all_status_flg(obj);
    
    return OD_OK;
}


static void sip_hdl_evt_malloc_free_delete(od_sip_hdl_evt_obj * obj)
{
    sip_hdl_evt_reset_all_status_flg(obj);
    pj_pool_reset(obj->ctx->pool); //FIXME: need a lock
}


static int sip_hdl_evt_process(od_sip_hdl_evt_obj *obj)
{
    sip_hdl_evt_monitor(obj);
        
    if (od_sip_get_event(obj->g_event_pipe, &obj->event) < 0) {
        od_msleep(50);
        return OD_OK;
    }

    return sip_hdl_evt_handle_event(obj);
}


od_sip_handle_event_handle od_sip_handle_event_create(od_sip_handle_event_static_params *static_params,
                                                        od_sip_handle_event_dynamic_params *dynamic_params)
{
    od_sip_hdl_evt_obj *obj = NULL;
    od_sip_handle_event_dynamic_params *params = NULL;

    OD_SIP_ASSERT_RETURN(static_params, NULL);
    OD_SIP_ASSERT_RETURN(static_params->h_state_machine, NULL);

    obj = od_task_create((char *)static_params->task_name, sizeof(od_sip_hdl_evt_obj));
    OD_SIP_ASSERT_RETURN(obj, NULL);

    obj->group_id = static_params->group_id;
    obj->h_state_machine = static_params->h_state_machine;
    obj->tab = od_sip_handle_event_dynamic_params_def;
    obj->params_nums = sizeof(od_sip_handle_event_dynamic_params_def) / sizeof(params_def) - 1;

    params = od_calloc(1, sizeof(od_sip_handle_event_dynamic_params));
    OD_SIP_ASSERT_RETURN(params, NULL);

    if (NULL == dynamic_params)
        memcpy(params, &glb_sip_handle_event_dynamic_params_default, sizeof(od_sip_handle_event_dynamic_params));
    else
        memcpy(params, dynamic_params, sizeof(od_sip_handle_event_dynamic_params));

    obj->params = (void *)params;
    obj->stack_size = SIP_HANDLE_EVENT_TSK_STACK_SIZE;
    obj->pf_start_stop  = (void *)sip_hdl_evt_start_stop;
    obj->pf_malloc_free = (void *)sip_hdl_evt_malloc_free;
    obj->pf_rt_set = NULL;
    obj->pf_process     = (void *)sip_hdl_evt_process;
    obj->pf_malloc_free_delete = (void *)sip_hdl_evt_malloc_free_delete;
    obj->pf_start_stop_delete = (void *)sip_hdl_evt_start_stop_delete;

    RPTDBG("create success");
    return (od_sip_handle_event_handle)obj;
}


/*_*/

